// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// This file contains the definitions of all possible generic NUC980 pins and their
// implementation using a combination of sysfs and memory-mapped I/O.

package nuc98x

import (
	"errors"
	"fmt"
	"openzbox.com/driver/conn/driver/driverreg"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"openzbox.com/driver/conn/gpio"
	"openzbox.com/driver/conn/gpio/gpioreg"
	"openzbox.com/driver/conn/physic"
	"openzbox.com/driver/conn/pin"
	"openzbox.com/driver/host/pmem"
	"openzbox.com/driver/host/sysfs"
	"openzbox.com/log"
)

// Pin implements the gpio.PinIO interface for generic Allwinner CPU pins using
// memory mapping for gpio in/out functionality.
type Pin struct {
	// Immutable.
	group       uint8     // as per register offset calculation
	offset      uint8     // as per register offset calculation
	name        string    // name as per datasheet
	defaultPull gpio.Pull // default pull at startup
	// Immutable after driver initialization.
	altFunc     [8]pin.Func // alternate functions
	sysfsPin    *sysfs.Pin  // Set to the corresponding sysfs.Pin, if any.
	available   bool        // Set when the pin is available on this CPU architecture.
	supportEdge bool        // Set when the pin supports interrupt based edge detection.
	// Mutable.
	usingEdge bool // Set when edge detection is enabled.
}

// Halt implements conn.Resource.
// It stops edge detection if enabled.
func (p *Pin) Halt() error {
	if p.usingEdge {
		if err := p.sysfsPin.Halt(); err != nil {
			return p.wrap(err)
		}
		p.usingEdge = false
	}
	return nil
}

// Name implements pin.Pin.
// It returns the pin name, ex: "PB5".
func (p *Pin) Name() string {
	return p.name
}

// Number implements pin.Pin.
// It returns the GPIO pin number as represented by gpio sysfs.
func (p *Pin) Number() int {
	return int(p.group)*32 + int(p.offset)
}

// Function implements pin.Pin.
func (p *Pin) Function() string {
	return string(p.Func())
}

// function returns the current GPIO pin function.
func (p *Pin) function() function {
	if drvGPIO.gpioMemory == nil {
		return disabled
	}
	shift := 4 * (p.offset % 8)
	return function((drvGPIO.gpioMemory.groups[p.group].MODE >> shift) & 7)
}

// Func implements pin.PinFunc.
func (p *Pin) Func() pin.Func {
	if !p.available {
		return pin.FuncNone
	}
	if drvGPIO.gpioMemory == nil {
		if p.sysfsPin == nil {
			return pin.FuncNone
		}
		return p.sysfsPin.Func()
	}
	switch f := p.function(); f {
	case in:
		if p.FastRead() {
			return gpio.IN_HIGH
		}
		return gpio.IN_LOW
	case out:
		if p.FastRead() {
			return gpio.OUT_HIGH
		}
		return gpio.OUT_LOW
	case alt1:
		if p.altFunc[0] != "" {
			return pin.Func(p.altFunc[0])
		}
		return pin.Func("ALT1")
	case alt2:
		if p.altFunc[1] != "" {
			if strings.Contains(string(p.altFunc[1]), "EINT") {
				// It's an input supporting interrupts.
				if p.FastRead() {
					return gpio.IN_HIGH
				}
				return gpio.IN_LOW
			}
			return pin.Func(p.altFunc[1])
		}
		return pin.Func("ALT2")
	case alt3:
		if p.altFunc[2] != "" {
			if strings.Contains(string(p.altFunc[2]), "EINT") {
				// It's an input supporting interrupts.
				if p.FastRead() {
					return gpio.IN_HIGH
				}
				return gpio.IN_LOW
			}
			return pin.Func(p.altFunc[2])
		}
		return pin.Func("ALT3")
	case alt4:
		if p.altFunc[3] != "" {
			if strings.Contains(string(p.altFunc[3]), "EINT") {
				// It's an input supporting interrupts.
				if p.FastRead() {
					return gpio.IN_HIGH
				}
				return gpio.IN_LOW
			}
			return pin.Func(p.altFunc[3])
		}
		return pin.Func("ALT4")
	case alt5:
		if p.altFunc[4] != "" {
			if strings.Contains(string(p.altFunc[4]), "EINT") {
				// It's an input supporting interrupts.
				if p.FastRead() {
					return gpio.IN_HIGH
				}
				return gpio.IN_LOW
			}
			return pin.Func(p.altFunc[4])
		}
		return pin.Func("ALT5")
	case alt6:
		if p.altFunc[5] != "" {
			return pin.Func(p.altFunc[5])
		}
		return pin.Func("ALT5")
	case alt7:
		if p.altFunc[6] != "" {
			return pin.Func(p.altFunc[6])
		}
		return pin.Func("ALT7")
	case alt8:
		if p.altFunc[7] != "" {
			return pin.Func(p.altFunc[7])
		}
		return pin.Func("ALT8")
	case disabled:
		return pin.FuncNone
	default:
		return pin.FuncNone
	}
}

// SupportedFuncs implements pin.PinFunc.
func (p *Pin) SupportedFuncs() []pin.Func {
	f := make([]pin.Func, 0, 2+8)
	f = append(f, gpio.IN, gpio.OUT)
	for _, m := range p.altFunc {
		if m != pin.FuncNone && !strings.Contains(string(m), "EINT") {
			f = append(f, m)
		}
	}
	return f
}

// SetFunc implements pin.PinFunc.
func (p *Pin) SetFunc(f pin.Func) error {
	switch f {
	case gpio.FLOAT:
		return p.In(gpio.Float, gpio.NoEdge)
	case gpio.IN:
		return p.In(gpio.PullNoChange, gpio.NoEdge)
	case gpio.IN_LOW:
		return p.In(gpio.PullDown, gpio.NoEdge)
	case gpio.IN_HIGH:
		return p.In(gpio.PullUp, gpio.NoEdge)
	case gpio.OUT_HIGH:
		return p.Out(gpio.High)
	case gpio.OUT_LOW:
		return p.Out(gpio.Low)
	default:
		isGeneral := f == f.Generalize()
		for i, m := range p.altFunc {
			if m == f || (isGeneral && m.Generalize() == f) {
				if err := p.Halt(); err != nil {
					return err
				}
				switch i {
				case 0:
					p.setFunction(alt1)
				case 1:
					p.setFunction(alt2)
				case 2:
					p.setFunction(alt3)
				case 3:
					p.setFunction(alt4)
				case 4:
					p.setFunction(alt5)
				case 5:
					p.setFunction(alt6)
				case 6:
					p.setFunction(alt7)
				case 7:
					p.setFunction(alt8)
				}
				return nil
			}
		}
		return p.wrap(errors.New("unsupported function"))
	}
}

// In implements gpio.PinIn.
// It sets the pin direction to input and optionally enables a pull-up/down
// resistor as well as edge detection.
// Not all pins support edge detection on NUC980 processors!
// Edge detection requires opening a gpio sysfs file handle. The pin will be
// exported at /sys/class/gpio/gpio*/. Note that the pin will not be unexported at shutdown.
func (p *Pin) In(pull gpio.Pull, edge gpio.Edge) error {
	if !p.available {
		// We do not want the error message about uninitialized system.
		return p.wrap(errors.New("not available on this CPU architecture"))
	}
	if edge != gpio.NoEdge && !p.supportEdge {
		return p.wrap(errors.New("edge detection is not supported on this pin"))
	}
	if p.usingEdge && edge == gpio.NoEdge {
		if err := p.sysfsPin.Halt(); err != nil {
			return p.wrap(err)
		}
		p.usingEdge = false
	}
	if drvGPIO.gpioMemory == nil {
		if p.sysfsPin == nil {
			return p.wrap(errors.New("subsystem gpiomem not initialized and sysfs not accessible; try running as root?"))
		}
		if pull != gpio.PullNoChange {
			return p.wrap(errors.New("pull cannot be used when subsystem gpiomem not initialized; try running as root?"))
		}
		if err := p.sysfsPin.In(pull, edge); err != nil {
			return p.wrap(err)
		}
		p.usingEdge = edge != gpio.NoEdge
		return nil
	}
	p.setFunction(in)
	if pull != gpio.PullNoChange {
		//off := p.offset / 16
		//shift := 2 * (p.offset % 16)
		// Do it in a way that is concurrency safe.
		//drvGPIO.gpioMemory.groups[p.group].pull |= (1 << (p.offset * 2)) // &^= 3 << shift
		switch pull {
		case gpio.PullDown:
			//		drvGPIO.gpioMemory.groups[p.group].pull = 2 << shift
		case gpio.PullUp:
			//		drvGPIO.gpioMemory.groups[p.group].pull = (1 << (p.offset * 2))//1 << shift
		default:
		}
	}
	if edge != gpio.NoEdge {
		if p.sysfsPin == nil {
			return p.wrap(fmt.Errorf("pin %d is not exported by sysfs", p.Number()))
		}
		// This resets pending edges.
		if err := p.sysfsPin.In(gpio.PullNoChange, edge); err != nil {
			return p.wrap(err)
		}
		p.usingEdge = true
	}
	return nil
}

// Read implements gpio.PinIn.
// It returns the current pin level. This function is fast.
func (p *Pin) Read() gpio.Level {
	if !p.available {
		return gpio.Low
	}
	if drvGPIO.gpioMemory == nil {
		if p.sysfsPin == nil {
			return gpio.Low
		}
		return p.sysfsPin.Read()
	}
	return gpio.Level(drvGPIO.gpioMemory.groups[p.group].PIN&(1<<p.offset) != 0)
}

// FastRead return the current pin level without any error checking.
// This function is very fast.
func (p *Pin) FastRead() gpio.Level {
	return gpio.Level(drvGPIO.gpioMemory.groups[p.group].PIN&(1<<p.offset) != 0)
}

// WaitForEdge implements gpio.PinIn.
// It waits for an edge as previously set using In() or the expiration of a timeout.
func (p *Pin) WaitForEdge(timeout time.Duration) bool {
	if p.sysfsPin != nil {
		return p.sysfsPin.WaitForEdge(timeout)
	}
	return false
}

// Pull implements gpio.PinIn.
func (p *Pin) Pull() gpio.Pull {
	if drvGPIO.gpioMemory == nil || !p.available {
		return gpio.PullNoChange
	}
	v := drvGPIO.gpioMemory.groups[p.group].pull
	pv := v >> (p.offset * 2) & 3
	/*
		log.Infof("xxxxxxx:%032b",pv)
		log.Infof("xxxxxxx:%032b",0&^pv)
		log.Infof("xxxxxxx:%d",0xff & 0x0c )
		log.Infof("xxxxxxx:%d",0xff&0x30 )
	*/
	switch pv {
	case 0:
		return gpio.PullNoChange
	case 1:
		return gpio.PullUp
	case 2:
		return gpio.PullDown
	default:
		// Confused.
		return gpio.PullNoChange
	}
	return gpio.Float
}

// DefaultPull implements gpio.PinIn.
func (p *Pin) DefaultPull() gpio.Pull {
	return p.defaultPull
}

// PWM implements gpio.PinOut.
func (p *Pin) PWM(gpio.Duty, physic.Frequency) error {
	return p.wrap(errors.New("not available on this CPU architecture"))
}

// Out implements gpio.PinOut.
func (p *Pin) Out(l gpio.Level) error {
	//drvGPIO.DebugX()
	if !p.available {
		// We do not want the error message about uninitialized system.
		return p.wrap(errors.New("not available on this CPU architecture"))
	}
	if drvGPIO.gpioMemory == nil {
		if p.sysfsPin != nil {
			return p.wrap(errors.New("subsystem gpiomem not initialized and sysfs not accessible; try running as root?"))
		}
		return p.sysfsPin.Out(l)
	}
	// First disable edges.
	if err := p.Halt(); err != nil {
		return err
	}
	//p.Pull()
	p.FastOut(l)
	p.setFunction(out)
	return nil
}

// FastOut sets a pin output level with Absolutely No error checking.
// Out() Must be called once first before calling FastOut(), otherwise the
// behavior is undefined. Then FastOut() can be used for minimal CPU overhead
// to reach Mhz scale bit banging.
func (p *Pin) FastOut(l gpio.Level) {
	bit := uint32(1 << p.offset)
	// Pn_DAT  n*0x24+0x10  Port n Data Register (n from 0(A) to 8(I))
	// This is a switch on p.group rather than an index to the groups array for
	// performance reasons: to avoid Go's array bound checking code.
	// See https://periph.io/news/2017/gpio_perf/ for details.
	idx := p.group
	if l {
		drvGPIO.gpioMemory.groups[idx].DOUT |= bit
	} else {
		drvGPIO.gpioMemory.groups[idx].DOUT &^= bit
	}
	//log.Infof("FastOut:%d  %32b",p.offset,bit)
}

// gpioGroup is a memory-mapped structure for the hardware registers that
// control a group of at most 32 pins. In practice the number of valid pins per
// group varies between 10 and 27.
type gpioGroup struct {
	// Pn_CFGx n*0x24+x*4       Port n Configure Register x (n from 1(B) to 7(H))
	//cfg [2]uint32
	MODE    uint32
	DINOFF  uint32
	DOUT    uint32
	DATMSK  uint32
	PIN     uint32
	DBEN    uint32
	INTTYPE uint32
	INTEN   uint32

	INTSRC  uint32
	SMTEN   uint32
	SLEWCTL uint32
	pull    uint32
	xx      [4]uint32
	// Pn_DRVx n*0x24+0x14+x*4  Port n Multi-Driving Register x (n from 1 to 7)
	//drv [2]uint32
	// Pn_PULL n*0x24+0x1C+x*4  Port n Pull Register (n from 1(B) to 7(H))
	//pull [2]uint32
}

// setFunction changes the GPIO pin function.
func (p *Pin) setFunction(f function) {
	//TODO 需要实现其他多功能定义，目前只定义输入输出
	if f > 1 {
		return
	}
	// 为1时配置为输出模式.0为输入模式，
	if f == 0 {
		drvGPIO.gpioMemory.groups[p.group].MODE &= ^uint32(1 << (p.offset * 2))
	} else {
		drvGPIO.gpioMemory.groups[p.group].MODE |= uint32(1 << (p.offset * 2))
	}
	/*
		 	if p.function() != f {
				panic(f)
			}*/
}

// A64: Page 23~24
// R8: Page 322-334.
// Each pin can have one of 7 functions.
const (
	in       function = 0
	out      function = 1
	alt1     function = 2
	alt2     function = 3
	alt3     function = 4
	alt4     function = 5
	alt5     function = 6 // often interrupt based edge detection as input
	alt6     function = 7 // often interrupt based edge detection as input
	alt7     function = 8 // often interrupt based edge detection as input
	alt8     function = 9 // often interrupt based edge detection as input
	disabled function = 10
)

// String implements conn.Resource.
// It returns the pin name and number, ex: "PB5(37)".
func (p *Pin) String() string {
	return fmt.Sprintf("%s(%d)", p.name, p.Number())
}

// List of all known pins. These global variables can be used directly.
// So make sure to read the datasheet for the exact right CPU.
var (
	PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12                   *Pin
	PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB13                                    *Pin
	PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15 *Pin
	PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15 *Pin
	PE0, PE1, PE2, PE3, PE4, PE5, PE6, PE7, PE8, PE9, PE10, PE11, PE12                   *Pin
	PF0, PF1, PF2, PF3, PF4, PF5, PF6, PF7, PF8, PF9, PF10, PF11, PF12                   *Pin
	PG0, PG1, PG3, PG5, PG6, PG7, PG8, PG9, PG10, PG11, PG12, PG13, PG14, PG15           *Pin
)

// cpupins that may be implemented by a generic nuc980 CPU. Not all pins
// will be present on all models and even if the CPU model supports them they
// may not be connected to anything on the board. The net effect is that it may
// look like more pins are available than really are, but trying to get the pin
// list 100% correct on all platforms seems futile, hence periph errs on the
// side of caution.
var cpupins = map[string]*Pin{
	"PA0":  {group: 0, offset: 0, name: "PA0", defaultPull: gpio.Float},
	"PA1":  {group: 0, offset: 1, name: "PA1", defaultPull: gpio.Float},
	"PA2":  {group: 0, offset: 2, name: "PA2", defaultPull: gpio.Float},
	"PA3":  {group: 0, offset: 3, name: "PA3", defaultPull: gpio.Float},
	"PA4":  {group: 0, offset: 4, name: "PA4", defaultPull: gpio.Float},
	"PA5":  {group: 0, offset: 5, name: "PA5", defaultPull: gpio.Float},
	"PA6":  {group: 0, offset: 6, name: "PA6", defaultPull: gpio.Float},
	"PA7":  {group: 0, offset: 7, name: "PA7", defaultPull: gpio.Float},
	"PA8":  {group: 0, offset: 8, name: "PA8", defaultPull: gpio.Float},
	"PA9":  {group: 0, offset: 9, name: "PA9", defaultPull: gpio.Float},
	"PA10": {group: 0, offset: 10, name: "PA10", defaultPull: gpio.Float},
	"PA11": {group: 0, offset: 11, name: "PA11", defaultPull: gpio.Float},
	"PA12": {group: 0, offset: 12, name: "PA12", defaultPull: gpio.Float},

	"PB0":  {group: 1, offset: 0, name: "PB0", defaultPull: gpio.Float},
	"PB1":  {group: 1, offset: 1, name: "PB1", defaultPull: gpio.Float},
	"PB2":  {group: 1, offset: 2, name: "PB2", defaultPull: gpio.Float},
	"PB3":  {group: 1, offset: 3, name: "PB3", defaultPull: gpio.Float},
	"PB4":  {group: 1, offset: 4, name: "PB4", defaultPull: gpio.Float},
	"PB5":  {group: 1, offset: 5, name: "PB5", defaultPull: gpio.Float},
	"PB6":  {group: 1, offset: 6, name: "PB6", defaultPull: gpio.Float},
	"PB7":  {group: 1, offset: 7, name: "PB7", defaultPull: gpio.Float},
	"PB8":  {group: 1, offset: 8, name: "PB8", defaultPull: gpio.Float},
	"PB13": {group: 1, offset: 13, name: "PB13", defaultPull: gpio.Float},

	"PC0":  {group: 2, offset: 0, name: "PC0", defaultPull: gpio.Float},
	"PC1":  {group: 2, offset: 1, name: "PC1", defaultPull: gpio.Float},
	"PC2":  {group: 2, offset: 2, name: "PC2", defaultPull: gpio.Float},
	"PC3":  {group: 2, offset: 3, name: "PC3", defaultPull: gpio.Float},
	"PC4":  {group: 2, offset: 4, name: "PC4", defaultPull: gpio.Float},
	"PC5":  {group: 2, offset: 5, name: "PC5", defaultPull: gpio.Float},
	"PC6":  {group: 2, offset: 6, name: "PC6", defaultPull: gpio.Float},
	"PC7":  {group: 2, offset: 7, name: "PC7", defaultPull: gpio.Float},
	"PC8":  {group: 2, offset: 8, name: "PC8", defaultPull: gpio.Float},
	"PC9":  {group: 2, offset: 9, name: "PC9", defaultPull: gpio.Float},
	"PC10": {group: 2, offset: 10, name: "PC10", defaultPull: gpio.Float},
	"PC11": {group: 2, offset: 11, name: "PC11", defaultPull: gpio.Float},
	"PC12": {group: 2, offset: 12, name: "PC12", defaultPull: gpio.Float},
	"PC13": {group: 2, offset: 13, name: "PC13", defaultPull: gpio.Float},
	"PC14": {group: 2, offset: 14, name: "PC14", defaultPull: gpio.Float},
	"PC15": {group: 2, offset: 15, name: "PC15", defaultPull: gpio.Float},

	"PD0":  {group: 3, offset: 0, name: "PD0", defaultPull: gpio.Float},
	"PD1":  {group: 3, offset: 1, name: "PD1", defaultPull: gpio.Float},
	"PD2":  {group: 3, offset: 2, name: "PD2", defaultPull: gpio.Float},
	"PD3":  {group: 3, offset: 3, name: "PD3", defaultPull: gpio.Float},
	"PD4":  {group: 3, offset: 4, name: "PD4", defaultPull: gpio.Float},
	"PD5":  {group: 3, offset: 5, name: "PD5", defaultPull: gpio.Float},
	"PD6":  {group: 3, offset: 6, name: "PD6", defaultPull: gpio.Float},
	"PD7":  {group: 3, offset: 7, name: "PD7", defaultPull: gpio.Float},
	"PD8":  {group: 3, offset: 8, name: "PD8", defaultPull: gpio.Float},
	"PD9":  {group: 3, offset: 9, name: "PD9", defaultPull: gpio.Float},
	"PD10": {group: 3, offset: 10, name: "PD10", defaultPull: gpio.Float},
	"PD11": {group: 3, offset: 11, name: "PD11", defaultPull: gpio.Float},
	"PD12": {group: 3, offset: 12, name: "PD12", defaultPull: gpio.Float},
	"PD13": {group: 3, offset: 13, name: "PD13", defaultPull: gpio.Float},
	"PD14": {group: 3, offset: 14, name: "PD14", defaultPull: gpio.Float},
	"PD15": {group: 3, offset: 15, name: "PD15", defaultPull: gpio.Float},

	"PE0":  {group: 4, offset: 0, name: "PE0", defaultPull: gpio.Float},
	"PE1":  {group: 4, offset: 1, name: "PE1", defaultPull: gpio.Float},
	"PE2":  {group: 4, offset: 2, name: "PE2", defaultPull: gpio.Float},
	"PE3":  {group: 4, offset: 3, name: "PE3", defaultPull: gpio.Float},
	"PE4":  {group: 4, offset: 4, name: "PE4", defaultPull: gpio.Float},
	"PE5":  {group: 4, offset: 5, name: "PE5", defaultPull: gpio.Float},
	"PE6":  {group: 4, offset: 6, name: "PE6", defaultPull: gpio.Float},
	"PE7":  {group: 4, offset: 7, name: "PE7", defaultPull: gpio.Float},
	"PE8":  {group: 4, offset: 8, name: "PE8", defaultPull: gpio.Float},
	"PE9":  {group: 4, offset: 9, name: "PE9", defaultPull: gpio.Float},
	"PE10": {group: 4, offset: 10, name: "PE10", defaultPull: gpio.Float},
	"PE11": {group: 4, offset: 11, name: "PE11", defaultPull: gpio.Float},
	"PE12": {group: 4, offset: 12, name: "PE12", defaultPull: gpio.Float},

	"PF0":  {group: 5, offset: 0, name: "PF0", defaultPull: gpio.Float},
	"PF1":  {group: 5, offset: 1, name: "PF1", defaultPull: gpio.Float},
	"PF2":  {group: 5, offset: 2, name: "PF2", defaultPull: gpio.Float},
	"PF3":  {group: 5, offset: 3, name: "PF3", defaultPull: gpio.Float},
	"PF4":  {group: 5, offset: 4, name: "PF4", defaultPull: gpio.Float},
	"PF5":  {group: 5, offset: 5, name: "PF5", defaultPull: gpio.Float},
	"PF6":  {group: 5, offset: 6, name: "PF6", defaultPull: gpio.Float},
	"PF7":  {group: 5, offset: 7, name: "PF7", defaultPull: gpio.Float},
	"PF8":  {group: 5, offset: 8, name: "PF8", defaultPull: gpio.Float},
	"PF9":  {group: 5, offset: 9, name: "PF9", defaultPull: gpio.Float},
	"PF10": {group: 5, offset: 10, name: "PF10", defaultPull: gpio.Float},
	"PF11": {group: 5, offset: 11, name: "PF11", defaultPull: gpio.Float},
	"PF12": {group: 5, offset: 12, name: "PF12", defaultPull: gpio.Float},

	"PG0": {group: 6, offset: 0, name: "PG0", defaultPull: gpio.Float},
	"PG1": {group: 6, offset: 1, name: "PG1", defaultPull: gpio.Float},
	//"PG2":  {group: 6, offset: 2, name: "PG2", defaultPull: gpio.Float},
	"PG3": {group: 6, offset: 3, name: "PG3", defaultPull: gpio.Float},
	//"PG4":  {group: 6, offset: 4, name: "PG4", defaultPull: gpio.Float},
	"PG5":  {group: 6, offset: 5, name: "PG5", defaultPull: gpio.Float},
	"PG6":  {group: 6, offset: 6, name: "PG6", defaultPull: gpio.Float},
	"PG7":  {group: 6, offset: 7, name: "PG7", defaultPull: gpio.Float},
	"PG8":  {group: 6, offset: 8, name: "PG8", defaultPull: gpio.Float},
	"PG9":  {group: 6, offset: 9, name: "PG9", defaultPull: gpio.Float},
	"PG10": {group: 6, offset: 10, name: "PG10", defaultPull: gpio.Float},
	"PG11": {group: 6, offset: 11, name: "PG11", defaultPull: gpio.Float},
	"PG12": {group: 6, offset: 12, name: "PG12", defaultPull: gpio.Float},
	"PG13": {group: 6, offset: 13, name: "PG13", defaultPull: gpio.Float},
	"PG14": {group: 6, offset: 14, name: "PG14", defaultPull: gpio.Float},
	"PG15": {group: 6, offset: 15, name: "PG15", defaultPull: gpio.Float},
}

func init() {
	PA0 = cpupins["PA0"]
	PA1 = cpupins["PA1"]
	PA2 = cpupins["PA2"]
	PA3 = cpupins["PA3"]
	PA4 = cpupins["PA4"]
	PA5 = cpupins["PA5"]
	PA6 = cpupins["PA6"]
	PA7 = cpupins["PA7"]
	PA8 = cpupins["PA8"]
	PA9 = cpupins["PA9"]
	PA10 = cpupins["PA10"]
	PA11 = cpupins["PA11"]
	PA12 = cpupins["PA12"]

	PB0 = cpupins["PB0"]
	PB1 = cpupins["PB1"]
	PB2 = cpupins["PB2"]
	PB3 = cpupins["PB3"]
	PB4 = cpupins["PB4"]
	PB5 = cpupins["PB5"]
	PB6 = cpupins["PB6"]
	PB7 = cpupins["PB7"]
	PB8 = cpupins["PB8"]
	PB13 = cpupins["PB13"]

	PC0 = cpupins["PC0"]
	PC1 = cpupins["PC1"]
	PC2 = cpupins["PC2"]
	PC3 = cpupins["PC3"]
	PC4 = cpupins["PC4"]
	PC5 = cpupins["PC5"]
	PC6 = cpupins["PC6"]
	PC7 = cpupins["PC7"]
	PC8 = cpupins["PC8"]
	PC9 = cpupins["PC9"]
	PC10 = cpupins["PC10"]
	PC11 = cpupins["PC11"]
	PC12 = cpupins["PC12"]
	PC13 = cpupins["PC13"]
	PC14 = cpupins["PC14"]
	PC15 = cpupins["PC15"]

	PD0 = cpupins["PD0"]
	PD1 = cpupins["PD1"]
	PD2 = cpupins["PD2"]
	PD3 = cpupins["PD3"]
	PD4 = cpupins["PD4"]
	PD5 = cpupins["PD5"]
	PD6 = cpupins["PD6"]
	PD7 = cpupins["PD7"]
	PD8 = cpupins["PD8"]
	PD9 = cpupins["PD9"]
	PD10 = cpupins["PD10"]
	PD11 = cpupins["PD11"]
	PD12 = cpupins["PD12"]
	PD13 = cpupins["PD13"]
	PD14 = cpupins["PD14"]
	PD15 = cpupins["PD15"]

	PE0 = cpupins["PE0"]
	PE1 = cpupins["PE1"]
	PE2 = cpupins["PE2"]
	PE3 = cpupins["PE3"]
	PE4 = cpupins["PE4"]
	PE5 = cpupins["PE5"]
	PE6 = cpupins["PE6"]
	PE7 = cpupins["PE7"]
	PE8 = cpupins["PE8"]
	PE9 = cpupins["PE9"]
	PE10 = cpupins["PE10"]
	PE11 = cpupins["PE11"]
	PE12 = cpupins["PE12"]

	PF0 = cpupins["PF0"]
	PF1 = cpupins["PF1"]
	PF2 = cpupins["PF2"]
	PF3 = cpupins["PF3"]
	PF4 = cpupins["PF4"]
	PF5 = cpupins["PF5"]
	PF6 = cpupins["PF6"]
	PF7 = cpupins["PF7"]
	PF8 = cpupins["PF8"]
	PF9 = cpupins["PF9"]
	PF10 = cpupins["PF10"]
	PF11 = cpupins["PF11"]
	PF12 = cpupins["PF12"]

	PG0 = cpupins["PG0"]
	PG1 = cpupins["PG1"]
	PG3 = cpupins["PG3"]
	PG5 = cpupins["PG5"]
	PG6 = cpupins["PG6"]
	PG7 = cpupins["PG7"]
	PG8 = cpupins["PG8"]
	PG9 = cpupins["PG9"]
	PG10 = cpupins["PG10"]
	PG11 = cpupins["PG11"]
	PG12 = cpupins["PG12"]
	PG13 = cpupins["PG13"]
	PG14 = cpupins["PG14"]
	PG15 = cpupins["PG15"]
}

func (p *Pin) wrap(err error) error {
	return fmt.Errorf("nuc98x-gpio (%s): %v", p, err)
}

// initPins initializes the mapping of pins by function, sets the alternate
// functions of each pin, and registers all the pins with gpio.
func initPins() error {

	functions := map[pin.Func]struct{}{}
	//fmt.Printf("xxxxxxx%v",sysfs.Pins[45])
	//取消sysfs/gpio 实现的所有GPIO注册
	//_ = gpioreg.UnregisterAll()
	//按实际引脚定义重新注册
	for name, p := range cpupins {
		num := strconv.Itoa(p.Number())
		gpion := "GPIO" + num
		// Unregister the pin if already registered. This happens with sysfs-gpio.
		// Do not error on it, since sysfs-gpio may have failed to load.
		_ = gpioreg.Unregister(gpion)
		_ = gpioreg.Unregister(num)
		// Register the pin with gpio.
		if err := gpioreg.Register(p); err != nil {
			return err
		}
		if err := gpioreg.RegisterAlias(gpion, name); err != nil {
			return err
		}
		if err := gpioreg.RegisterAlias(num, name); err != nil {
			return err
		}
		switch f := p.Func(); f {
		case gpio.IN, gpio.OUT, pin.FuncNone:
		default:
			// Registering the same alias twice fails. This can happen if two pins
			// are configured with the same function.
			if _, ok := functions[f]; !ok {
				functions[f] = struct{}{}
				if err := gpioreg.RegisterAlias(string(f), name); err != nil {
					return err
				}
			}
		}

	}
	// Now do a second loop but do the alternate functions.
	for name, p := range cpupins {
		for _, f := range p.SupportedFuncs() {
			switch f {
			case gpio.IN, gpio.OUT:
			default:
				if _, ok := functions[f]; !ok {
					functions[f] = struct{}{}
					if err := gpioreg.RegisterAlias(string(f), name); err != nil {
						return err
					}
				}
			}
		}
		//fmt.Printf("xxxxxxx%s,%v", name, p)
	}
	return nil
}

// function encodes the active functionality of a pin. The alternate functions
// are GPIO pin dependent.
type function uint8

// gpioMap memory-maps all the gpio pin groups.
// NUC980 has PA-PG 7 ports
type gpioMap struct {
	// PA to PI.
	groups [7]gpioGroup
}

// driverGPIO implements periph.Driver.
type driverGPIO struct {
	// gpioMemory is the memory map of the CPU GPIO registers.
	gpioMemory *gpioMap
}

func (d *driverGPIO) String() string {
	return "nuc98x-gpio"
}

func (d *driverGPIO) Prerequisites() []string {
	return nil
}

func (d *driverGPIO) After() []string {
	return []string{"sysfs-gpio"}
}

// Init does nothing if an allwinner processor is not detected. If one is
// detected, it memory maps gpio CPU registers and then sets up the pin mapping
// for the exact processor model detected.
func (d *driverGPIO) Init() (bool, error) {
	if !Present() {
		return false, errors.New("no Nuvoton CPU detected")
	}
	// Mark the right pins as available even if the memory map fails so they can
	// callback to sysfs.Pins.
	switch {
	case IsDK61YC():
		if err := mapDK61YCPins(); err != nil {
			return true, err
		}
	case IsDK61Y():
		//TODO 61yc不带CAN
		/*
			if err := mapR8Pins(); err != nil {
				return true, err
			}*/
	case IsDR61Y():
		if err := mapDR61YPins(); err != nil {
			return true, err
		}
	default:
		return false, errors.New("unknown Nuvoton CPU model")
	}
	// gpioBaseAddr is the physical base address of the GPIO registers.
	gpioBaseAddr := uint32(getBaseAddress())
	if err := pmem.MapAsPOD(uint64(gpioBaseAddr), &d.gpioMemory); err != nil {
		if os.IsPermission(err) {
			return true, fmt.Errorf("need more access, try as root: %v", err)
		}
		return true, err
	}
	return true, initPins()
}

func (d *driverGPIO) DebugX() {
	log.Infof("GPIOA gpioMemory:%v ", d.gpioMemory.groups[0])
	log.Warnf("GPIOB gpioMemory:%v ", d.gpioMemory.groups[1])
	log.Infof("GPIOC gpioMemory:%v ", d.gpioMemory.groups[2])
	log.Infof("GPIOD gpioMemory:%v ", d.gpioMemory.groups[3])
	log.Infof("GPIOE gpioMemory:%v ", d.gpioMemory.groups[4])
	log.Infof("GPIOF gpioMemory:%v ", d.gpioMemory.groups[5])
	log.Infof("GPIOG gpioMemory:%v ", d.gpioMemory.groups[6])
}

func init() {
	if isArm {
		driverreg.MustRegister(&drvGPIO)
	}
}

// getBaseAddress queries the virtual file system to retrieve the base address
// of the GPIO registers for GPIO pins in groups PA to PI.
// see NUC980_TechnicalReferenceManual_EN_Rev1.00.pdf page 262
// Defaults to 0xB0004000 as per datasheet if it could not query the file
// system.
func getBaseAddress() uint64 {
	base := uint64(0xB0004000)
	link, err := os.Readlink("/sys/bus/platform/drivers/pinctrl-nuc980/pinctrl-nuc980/driver")
	//log.Infof("xxxxxxx:%s %v",link,err)
	if err != nil {
		return base
	}
	parts := strings.SplitN(path.Base(link), ".", 2)
	if len(parts) != 2 {
		return base
	}
	base2, err := strconv.ParseUint(parts[0], 16, 64)
	if err != nil {
		return base
	}
	return base2
}

var drvGPIO driverGPIO

// Ensure that the various structs implement the interfaces they're supposed to.
var _ gpio.PinIO = &Pin{}
var _ gpio.PinIn = &Pin{}
var _ gpio.PinOut = &Pin{}
var _ pin.PinFunc = &Pin{}
